﻿#ifndef VARIANT_H
#define VARIANT_H

#include <string>
#include <memory>
#include <vector>
#include <map>
#include <iostream>
#include <type_traits>

#include <metatype.h>



REFLECTX_EXPORT DataOutputStream& operator << (DataOutputStream& s, const Variant& t);
REFLECTX_EXPORT DataInputStream& operator >> (DataInputStream& s, Variant& t) throw (StreamException);

class REFLECTX_EXPORT Variant
{
public:
    Variant(const void* data,MetaTypeId type);
    Variant();
    Variant(const Variant& other);

    Variant(const int& v);
    Variant(const double& v);
    Variant(const float& v);
    Variant(const std::string& v);
    Variant(const std::wstring& v);
    Variant(const VariantList& list);
    Variant(const VariantWMap& map);

    Variant& operator =(const Variant& other);
    bool operator ==(const Variant& other) const;


    bool isValid() const;
    MetaTypeId TypeId() const;
    std::string TypeName() const;

    bool Convertable(MetaTypeId targetId);
    bool Convert(MetaTypeId targetId);

    void* data();//获取内部数据指针
    const void* data() const;

    void AsignTo(void* data);

    template<typename T>
    static Variant FromValue(const T& val){
        if(!MetaType::IsTypeDeclared<T>()){
            std::cout<<"type not Declared!"<<std::endl;
        }
        int id = MetaType::IdFromType<T>();
        Variant r = FromValue((void*)&val,id);
        return r;
    }

    template<typename T>
    typename std::enable_if<!std::is_same<T,Variant>::value,T>::type Value() const{
        if(!MetaType::IsTypeDeclared<T>()){
            std::cout<<"type not Declared!"<<std::endl;
        }

        int id = MetaType::IdFromType<T>();

		T t;
		bool ok;
		Value(&t,id,ok);

		return t;
    }

    template<typename T>
    typename std::enable_if<std::is_same<T,Variant>::value,T>::type Value() const{
        return *this;
    }

    static Variant FromType(MetaTypeId id);

	//转换为可用于反射调用的指针参数，该指针可能指向内部数据，也可能指向自己，如果类型不相同则进行类型转换
	static const void* BeReadyForParam(Variant& var, MetaTypeId targetid);
	//转换为可用于反射调用的返回值参数
	static void* BeReadyForReturn(Variant& var, MetaTypeId targetid);
private:
    static Variant FromValue(const void* value,int typeId);
    void Value(void* output,int typeId,bool &ok) const;

private:
    int type_id;
    std::shared_ptr<void> m_data;
};

#endif // VARIANT_H
